package com.yourenbang.lingyun.transaction.web.service.impl.fund.fundopt;

import com.yourenbang.lingyun.constants.BizCodeMessages;
import com.yourenbang.lingyun.constants.enums.PlatNoEnums;
import com.yourenbang.lingyun.constants.enums.fund.AccountMainJournalType;
import com.yourenbang.lingyun.constants.enums.fund.AccountType;
import com.yourenbang.lingyun.core.exception.BizRuntimeException;
import com.yourenbang.lingyun.core.exception.UserBizException;
import com.yourenbang.lingyun.core.message.Result;
import com.yourenbang.lingyun.core.util.BizAssertUtils;
import com.yourenbang.lingyun.core.util.KLog;
import com.yourenbang.lingyun.domain.FundAccount;
import com.yourenbang.lingyun.mapper.FundAccountMapper;
import com.yourenbang.lingyun.transaction.constant.ChangePlanStatus;
import com.yourenbang.lingyun.transaction.constant.ChangeTypeConstant;
import com.yourenbang.lingyun.transaction.constant.JournalStatus;
import com.yourenbang.lingyun.transaction.mapper.TransactionFundAccountChangePlanMapper;
import com.yourenbang.lingyun.transaction.mapper.TransactionFundAccountJournalMapper;
import com.yourenbang.lingyun.transaction.mapper.TransactionFundAccountMapper;
import com.yourenbang.lingyun.transaction.web.domain.po.FundAccountChangePlan;
import com.yourenbang.lingyun.transaction.web.domain.po.FundAccountJournal;
import com.yourenbang.lingyun.transaction.web.domain.vo.JournalInfoVO;
import com.yourenbang.lingyun.transaction.web.service.fund.fundopt.FundOptUndepositService;
import com.yourenbang.transaction.api.service.fund.FundBillService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Objects;

@Slf4j
@Service
public class FundOptUndepositServiceImpl implements FundOptUndepositService {
    @Resource
    private TransactionFundAccountMapper transactionFundAccountMapper;
    @Resource
    private FundAccountMapper fundAccountMapper;
    @Resource
    private FundBillService fundBillService;
    @Resource
    private TransactionFundAccountChangePlanMapper fundAccountChangePlanMapper;
    @Resource
    private TransactionFundAccountJournalMapper fundAccountJournalMapper;


    @Transactional
    @Override
    public Result undeposit(FundAccountChangePlan fundAccountChangePlan) {

        if (!(fundAccountChangePlan.getAccountChangePlanStatus() == ChangePlanStatus.CHANGING ||
                fundAccountChangePlan.getAccountChangePlanStatus() == ChangePlanStatus.WAIT_TO_CHANGE)
        ) {
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "计划变更不可解冻");
        }

        //用户账户
        FundAccount toFundAccount = fundAccountMapper.selectByPrimaryKey(fundAccountChangePlan.getToFundAccountId());
        if (Objects.isNull(toFundAccount)) {
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "用户账户不存在");
        }

        //设置资金主类型
        AccountMainJournalType accountMainJournalType;

        if (AccountType.getFullCode(AccountType.MER, PlatNoEnums.YXY.getCode()).equals(toFundAccount.getAccountType())) {
            accountMainJournalType = AccountMainJournalType.MERCHANT_OUT;
        } else {
            accountMainJournalType = AccountMainJournalType.ALLY_V2_OUT;
        }

        AccountType toAccountType = AccountType.getAccountTypeByFullCode(toFundAccount.getAccountType());
        JournalInfoVO journalVO = ChangeTypeConstant.getSubtractJournalTypeV2(toAccountType, accountMainJournalType);

        //资金发起账户
        FundAccount fromFundAccount = fundAccountMapper.selectByPrimaryKey(fundAccountChangePlan.getFundAccountId());
        if (Objects.isNull(fromFundAccount)) {
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "系统账户不存在");
        }


        try {

            //资金发起方解冻 冻结中的金额-;已提现金额+;
            int i = transactionFundAccountMapper.frozenUndeposit(fromFundAccount.getFundAccountId(), fundAccountChangePlan.getChangeAmount());
            BizAssertUtils.assertOne(i, "解冻用户金额失败");

            //记录资金发起方流水
            FundAccountJournal journal = getFromFundAccountJournal(fromFundAccount, journalVO, fundAccountChangePlan);
            fundAccountJournalMapper.insert(journal);


            //资金接收方解冻 冻结中的金额-;已提现金额+;
            int y = transactionFundAccountMapper.frozenUndeposit(toFundAccount.getFundAccountId(), fundAccountChangePlan.getChangeAmount());
            BizAssertUtils.assertOne(y, "解冻金额失败");

            //记录资金接收起方流水
            FundAccountJournal toJournal = getToFundAccountJournal(toFundAccount, journalVO, fundAccountChangePlan);
            fundAccountJournalMapper.insert(toJournal);


            //变动成功
            FundAccountChangePlan upChange = new FundAccountChangePlan(fundAccountChangePlan.getPlatNo());
            upChange.setFundAccountChangePlanId(fundAccountChangePlan.getFundAccountChangePlanId());
            upChange.setAccountChangePlanStatus(ChangePlanStatus.CHANGED);
            int upChangeCount = fundAccountChangePlanMapper.updateById(upChange);
            BizAssertUtils.assertOne(upChangeCount, "更新资金变动表失败");

        } catch (UserBizException e) {

            KLog.warn("【提现】扣掉冻结金额,异常:{}, 资金变动记录:{}", e.getMessage(), fundAccountChangePlan.toString(), e);
            return Result.builder().fail(BizCodeMessages.TRANSACTION_PLEDGE_CHECKING);

        } catch (BizRuntimeException e) {

            KLog.error("【提现】扣掉冻结金额,异常:{}, 资金变动记录:{}", e.getMessage(), fundAccountChangePlan.toString(), e);
            return Result.builder().fail(BizCodeMessages.TRANSACTION_PLEDGE_CHECKING);

        }

        return Result.builder().success();

    }

    @Transactional
    @Override
    public Result undepositBalancePay(FundAccountChangePlan fundAccountChangePlan) {

        if (!(fundAccountChangePlan.getAccountChangePlanStatus() == ChangePlanStatus.CHANGING ||
                fundAccountChangePlan.getAccountChangePlanStatus() == ChangePlanStatus.WAIT_TO_CHANGE)
        ) {
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "计划变更不可解冻");
        }

        //接收方账户
        FundAccount toFundAccount = fundAccountMapper.selectByPrimaryKey(fundAccountChangePlan.getToFundAccountId());
        if (Objects.isNull(toFundAccount)) {
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "接收方账户不存在");
        }

        AccountType toAccountType = AccountType.getAccountTypeByFullCode(toFundAccount.getAccountType());
        JournalInfoVO journalVO = ChangeTypeConstant.getSubtractJournalTypeV2(toAccountType, AccountMainJournalType.ALLY_V2_OUT);

        //发起方账户
        FundAccount fromFundAccount = fundAccountMapper.selectByPrimaryKey(fundAccountChangePlan.getFundAccountId());
        if (Objects.isNull(fromFundAccount)) {
            throw new BizRuntimeException(BizCodeMessages.UNKNOWN_ERROR, "发起账户不存在");
        }


        try {

            //资金发起方解冻 冻结中的金额-;已提现金额+;
            int i = transactionFundAccountMapper.frozenUndeposit(fromFundAccount.getFundAccountId(), fundAccountChangePlan.getChangeAmount());
            BizAssertUtils.assertOne(i, "解冻用户金额失败");

            //记录资金发起方流水
            FundAccountJournal journal = getFromFundAccountJournal(fromFundAccount, journalVO, fundAccountChangePlan);
            fundAccountJournalMapper.insert(journal);


            //资金接收方 收入+;可提+;
            int y = transactionFundAccountMapper.incomeAdd(toFundAccount.getFundAccountId(), fundAccountChangePlan.getChangeAmount());
            BizAssertUtils.assertOne(y, "加帐失败");

            //记录资金接收起方流水
            FundAccountJournal toJournal = getToFundAccountBalancePayJournal(toFundAccount, journalVO, fundAccountChangePlan);
            fundAccountJournalMapper.insert(toJournal);


            //变动成功
            FundAccountChangePlan upChange = new FundAccountChangePlan(fundAccountChangePlan.getPlatNo());
            upChange.setFundAccountChangePlanId(fundAccountChangePlan.getFundAccountChangePlanId());
            upChange.setAccountChangePlanStatus(ChangePlanStatus.CHANGED);
            int upChangeCount = fundAccountChangePlanMapper.updateById(upChange);
            BizAssertUtils.assertOne(upChangeCount, "更新资金变动表失败");

            // bill账单冻结动作时已经写入,此时无需再写

        } catch (UserBizException e) {

            KLog.warn("【提现】扣掉冻结金额,异常:{}, 资金变动记录:{}", e.getMessage(), fundAccountChangePlan.toString(), e);
            return Result.builder().fail(BizCodeMessages.TRANSACTION_PLEDGE_CHECKING);

        } catch (BizRuntimeException e) {

            KLog.error("【提现】扣掉冻结金额,异常:{}, 资金变动记录:{}", e.getMessage(), fundAccountChangePlan.toString(), e);
            return Result.builder().fail(BizCodeMessages.TRANSACTION_PLEDGE_CHECKING);

        }

        return Result.builder().success();

    }

    private FundAccountJournal getToFundAccountJournal(FundAccount toFundAccount, JournalInfoVO journalVO,
                                                       FundAccountChangePlan changePlan) {

        //记录接收资金方流水
        FundAccountJournal journal = new FundAccountJournal(changePlan.getPlatNo());
        journal.setChannelId(changePlan.getChannelId());
        journal.setFundAccountChangePlanId(changePlan.getFundAccountChangePlanId());
        journal.setFundAccountId(toFundAccount.getFundAccountId());
        journal.setJournalStatus(JournalStatus.SUCCESS);
        journal.setJournalChangeValue(changePlan.getChangeAmount());
        journal.setAccountJournalAcid(changePlan.getOrderId());

        journal.setAccountMainJournalType(journalVO.getAccountMainJournalType().getCode());
        journal.setAccountMainJournalTypeName(journalVO.getAccountMainJournalType().getName());

        journal.setAccountIncome(BigDecimal.ZERO);            //收入资金变动金额
        journal.setAccountAmountFrozen(changePlan.getChangeAmount());   //冻结资金变动收入
        journal.setAccountAmountWithdrawable(BigDecimal.ZERO);    //可提现资金变动收入
        journal.setAccountAmountWithdrawed(changePlan.getChangeAmount());  //已提现资金变动收入
        journal.setAccountAmountUndepositable(BigDecimal.ZERO);   //不可提现资金变动收入

        journal.setAccountIncomeBefore(toFundAccount.getAccountIncome());      //收入变动前的金额
        journal.setAccountIncomeAfterwards(toFundAccount.getAccountIncome());  //收入变动后的金额

        journal.setAccountAmountFrozenBefore(toFundAccount.getAccountAmountFrozen());   //冻结资金变化前金额
        journal.setAccountAmountFrozenAfterwards(toFundAccount.getAccountAmountFrozen().subtract(changePlan.getChangeAmount())); //冻结资金变化后金额

        journal.setAccountAmountWithdrawableBefore(toFundAccount.getAccountAmountWithdrawable());   //可提现金额变化前金额
        journal.setAccountAmountWithdrawableAfterwards(toFundAccount.getAccountAmountWithdrawable()); //可提现金额变化后金额

        journal.setAccountAmountWithdrawedBefore(toFundAccount.getAccountAmountWithdrawed());        //已提现金额变化前金额
        journal.setAccountAmountWithdrawedAfterwards(toFundAccount.getAccountAmountWithdrawed().add(changePlan.getChangeAmount()));    //已提现金额变化后金额

        journal.setAccountAmountUndepositableBefore(toFundAccount.getAccountAmountUndepositable());     //不可提现金额变化前金额
        journal.setAccountAmountUndepositableAfterwards(toFundAccount.getAccountAmountUndepositable()); //不可提现金额变化后金额


        return journal;

    }

    private FundAccountJournal getFromFundAccountJournal(FundAccount fromFundAccount, JournalInfoVO journalVO,
                                                         FundAccountChangePlan changePlan) {

        //记录发起方资金方流水
        FundAccountJournal journal = new FundAccountJournal(changePlan.getPlatNo());
        journal.setChannelId(changePlan.getChannelId());
        journal.setFundAccountChangePlanId(changePlan.getFundAccountChangePlanId());
        journal.setFundAccountId(fromFundAccount.getFundAccountId());
        journal.setJournalStatus(JournalStatus.SUCCESS);
        journal.setJournalChangeValue(changePlan.getChangeAmount());
        journal.setAccountJournalAcid(changePlan.getOrderId());

        journal.setAccountMainJournalType(journalVO.getAccountMainJournalType().getCode());
        journal.setAccountMainJournalTypeName(journalVO.getAccountMainJournalType().getName());

        journal.setAccountIncome(BigDecimal.ZERO);            //收入资金变动金额
        journal.setAccountAmountFrozen(changePlan.getChangeAmount());   //冻结资金变动收入
        journal.setAccountAmountWithdrawable(BigDecimal.ZERO);    //可提现资金变动收入
        journal.setAccountAmountWithdrawed(changePlan.getChangeAmount());  //已提现资金变动收入
        journal.setAccountAmountUndepositable(BigDecimal.ZERO);   //不可提现资金变动收入

        journal.setAccountIncomeBefore(fromFundAccount.getAccountIncome());      //收入变动前的金额
        journal.setAccountIncomeAfterwards(fromFundAccount.getAccountIncome());  //收入变动后的金额

        journal.setAccountAmountFrozenBefore(fromFundAccount.getAccountAmountFrozen());   //冻结资金变化前金额
        journal.setAccountAmountFrozenAfterwards(fromFundAccount.getAccountAmountFrozen().subtract(changePlan.getChangeAmount())); //冻结资金变化后金额

        journal.setAccountAmountWithdrawableBefore(fromFundAccount.getAccountAmountWithdrawable());   //可提现金额变化前金额
        journal.setAccountAmountWithdrawableAfterwards(fromFundAccount.getAccountAmountWithdrawable()); //可提现金额变化后金额

        journal.setAccountAmountWithdrawedBefore(fromFundAccount.getAccountAmountWithdrawed());        //已提现金额变化前金额
        journal.setAccountAmountWithdrawedAfterwards(fromFundAccount.getAccountAmountWithdrawed().add(changePlan.getChangeAmount()));    //已提现金额变化后金额

        journal.setAccountAmountUndepositableBefore(fromFundAccount.getAccountAmountUndepositable());     //不可提现金额变化前金额
        journal.setAccountAmountUndepositableAfterwards(fromFundAccount.getAccountAmountUndepositable()); //不可提现金额变化后金额

        return journal;
    }

    private FundAccountJournal getToFundAccountBalancePayJournal(FundAccount toFundAccount, JournalInfoVO journalVO,
                                                                 FundAccountChangePlan changePlan) {

        BigDecimal accountIncomeAfter = toFundAccount.getAccountIncome().add(changePlan.getChangeAmount());
        BigDecimal accountAmountWithdrawableAfter = toFundAccount.getAccountAmountWithdrawable().add(changePlan.getChangeAmount());

        //记录接收资金方流水
        FundAccountJournal journal = new FundAccountJournal(changePlan.getPlatNo());
        journal.setChannelId(changePlan.getChannelId());
        journal.setFundAccountChangePlanId(changePlan.getFundAccountChangePlanId());
        journal.setFundAccountId(toFundAccount.getFundAccountId());
        journal.setJournalStatus(JournalStatus.SUCCESS);
        journal.setJournalChangeValue(changePlan.getChangeAmount());
        journal.setAccountJournalAcid(changePlan.getOrderId());

        journal.setAccountMainJournalType(journalVO.getAccountMainJournalType().getCode());
        journal.setAccountMainJournalTypeName(journalVO.getAccountMainJournalType().getName());

        journal.setAccountIncome(changePlan.getChangeAmount());            //收入资金变动金额
        journal.setAccountAmountFrozen(BigDecimal.ZERO);   //冻结资金变动收入
        journal.setAccountAmountWithdrawable(changePlan.getChangeAmount());    //可提现资金变动收入
        journal.setAccountAmountWithdrawed(BigDecimal.ZERO);  //已提现资金变动收入
        journal.setAccountAmountUndepositable(BigDecimal.ZERO);   //不可提现资金变动收入

        journal.setAccountIncomeBefore(toFundAccount.getAccountIncome());      //收入变动前的金额
        journal.setAccountIncomeAfterwards(accountIncomeAfter);  //收入变动后的金额

        journal.setAccountAmountFrozenBefore(toFundAccount.getAccountAmountFrozen());   //冻结资金变化前金额
        journal.setAccountAmountFrozenAfterwards(toFundAccount.getAccountAmountFrozen()); //冻结资金变化后金额

        journal.setAccountAmountWithdrawableBefore(toFundAccount.getAccountAmountWithdrawable());   //可提现金额变化前金额
        journal.setAccountAmountWithdrawableAfterwards(accountAmountWithdrawableAfter); //可提现金额变化后金额

        journal.setAccountAmountWithdrawedBefore(toFundAccount.getAccountAmountWithdrawed());        //已提现金额变化前金额
        journal.setAccountAmountWithdrawedAfterwards(toFundAccount.getAccountAmountWithdrawed());    //已提现金额变化后金额

        journal.setAccountAmountUndepositableBefore(toFundAccount.getAccountAmountUndepositable());     //不可提现金额变化前金额
        journal.setAccountAmountUndepositableAfterwards(toFundAccount.getAccountAmountUndepositable()); //不可提现金额变化后金额


        return journal;

    }
}
